/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package deatax;

import deatax.unit.Unit;
import deatax.unit.UnitStack;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

/**
 *
 * @author nrechten
 */
public class Tile {

    ArrayList<Tile> neighbours = new ArrayList<Tile>();
    private Tile[] neighbourMap = new Tile[6];
    int x, y;
    //The type of terrain of this tile
    private Terrain terrain;
    //What improvement is built on this tile. null for nothing
    private Improvement improvement;
    //Which player owns this improvement. null for none
    private Player owner;
    private Region region;
    private HashMap<Player, ArrayList<UnitStack>> units;
    private TilePopulation population;
//    private List<Marker> markers = new ArrayList<Marker>();
    private float[] mark_pos;
    
    private boolean hover;

    
    private int modelIndex = 0;
    private int textureIndex = 0;

    public Tile() {
        owner = null;
        improvement = null;
        units = new HashMap<Player, ArrayList<UnitStack>>();
        population = null;
        //markers.add(new PlayerMarker(null));
    }

    public Tile(int x, int y, Region region) {
        this();
        this.x = x;
        this.y = y;
        this.region = region;
        this.terrain = null;//new Terrain("Plain", null, 0,null);
    }

    public void setOwner(Player owner) {
        if (this.owner != null) {
//            this.owner.removeTile(this);
//            Marker rem = null;
//            for (Marker m : getMarkers()) {
//                if (m instanceof PlayerMarker) {
//                    rem = m;
//                }
//            }
//            if (rem != null) {
//                getMarkers().remove(rem);
//            }
        }
        this.owner = owner;
        if (this.owner != null) {
            this.owner.addTile(this);
//            getMarkers().add(new PlayerMarker(owner));
        }
    }

    public int getMoveCost(Player context, boolean water) {
        int total = (water ? terrain.getWaterCost() : terrain.getMoveCost());
        if (context != null && improvement != null) {
            if (owner == context && improvement instanceof Road) {
                total -= (water ? ((Road)improvement).getWaterBonus() : ((Road) improvement).getMoveBonus());
                if (total < 0) {
                    total = 0;
                }
            }
        }
        return total;
    }

    public void tireUnits(Player p, Unit u, int num) {
        if (!units.containsKey(p)) {
            return;
        }
        ArrayList<UnitStack> au = getUnits().get(p);
        if (!au.isEmpty()) {
            UnitStack unit = null;
            for (UnitStack fu : au) {
                if (fu.getType().equals(u)) {
                    unit = fu;
                    break;
                }
            }
            if (unit != null) {
                unit.tire(num);
            }
        }
    }

    public void addUnit(Player p, Unit u, int num) {
        if (!units.containsKey(p)) {
            getUnits().put(p, new ArrayList<UnitStack>());
        }
        ArrayList<UnitStack> au = getUnits().get(p);
        if (au.isEmpty()) {
            au.add(new UnitStack(p, this, u, num));
        } else {
            UnitStack unit = null;
            for (UnitStack fu : au) {
                if (fu.getType().equals(u)) {
                    unit = fu;
                    break;
                }
            }
            if (unit == null) {
                au.add(new UnitStack(p, this, u, num));
            } else {
                unit.add(num);
            }
        }
        if (!getUnits(p).isEmpty()) {
            p.addUnit(this);
        }
    }

    public void removeUnit(Player p, Unit u, int num) {
        if (!units.containsKey(p)) {
            return;
        }
        ArrayList<UnitStack> au = getUnits().get(p);
        if (au.isEmpty()) {
            return;
        }
        UnitStack unit = null;
        for (UnitStack fu : au) {
            if (fu.getType().equals(u)) {
                unit = fu;
                break;
            }
        }
        if (unit == null) {
            return;
        } else {
            if (unit.getAmount() - num <= 0) {
                au.remove(unit);
            } else {
                unit.add(-num);
            }
        }
        
        if (getUnits(p).isEmpty()) {
            p.removeUnit(this);
        }
    }

    public ArrayList<UnitStack> getUnits(Player p) {
        if (!units.containsKey(p)) {
            getUnits().put(p, new ArrayList<UnitStack>());
        }
        return getUnits().get(p);
    }

    //Will find the specified player's units first
    public ArrayList<UnitStack> getAllUnits(Player p) {
        ArrayList<UnitStack> list = new ArrayList<UnitStack>();

        if (p != null) {
            if (!units.containsKey(p)) {
                units.put(p, new ArrayList<UnitStack>());
            }
            list.addAll(units.get(p));
        }
        for (Entry<Player, ArrayList<UnitStack>> e : units.entrySet()) {
            if (e.getKey() != p) {
                list.addAll(e.getValue());
            }
        }
        return list;
    }

    public Player getOwner() {
        return owner;
    }

    public Improvement getImprovement() {
        return improvement;
    }

    public void setImprovement(Improvement improvement) {
        if (this.improvement instanceof Settlement && improvement == null) {

            owner.removeSettle(this);
        }
        this.improvement = improvement;
//        if(improvement != null){
//            markers.add(improvement.getMarkerRenderer(owner));
//        }
        if (improvement != null && improvement instanceof Settlement) {
//            for (Tile neigh : getNeighbours()) {
//                neigh.setOwner(owner);
//            }
            owner.addSettle(this);
            Settlement s = (Settlement) improvement;

            if (s.getBasePopulation() > 0) {
                this.population = new TilePopulation();
                addPopulation(s.getBasePopulation());
            }
        }
    }

    public int getPopulation() {
        if (population == null) {
            return 0;
        }
        return population.getCurrentPopulation();
    }

    //returns whether has hit max
    public int addPopulation(int n) {
        if (population == null) {
            return 0;
        }
        Settlement s = (Settlement)improvement;
        int pop = population.addPopulation(n, s.getMaxPopulation());
        getOwner().firePopulationListeners(pop);
        return pop;
        
    }

    public Terrain getTerrain() {
        return terrain;
    }

    public void setTerrain(Terrain terrain) {
        this.terrain = terrain;
        this.setModelIndex(terrain.getNextModelIndex());
        this.setTextureIndex(terrain.getNextTextureIndex());
    }

    public ArrayList<Tile> getNeighbours() {
        return neighbours;
    }

    

    public Color getColour() {
        return region.getColour();
    }

    public Region getRegion() {
        return region;
    }

    public boolean partOf(Region r) {
        return r == region;
    }

    

    public void onHoverIn() {
        region.setColour(region.getColour().brighter());
        setHover(true);
    }

    public void onHoverOut() {
        setHover(false);
        region.setColour(region.getColour().darker());
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public void addNeigbour(Tile t, int direction) {
        neighbours.add(t);
        neighbourMap[direction%6] = t;
    }

    /**
     * @return the hover
     */
    public boolean isHover() {
        return hover;
    }

    /**
     * @param hover the hover to set
     */
    public void setHover(boolean hover) {
        this.hover = hover;
    }

    /**
     * @return the modelIndex
     */
    public int getModelIndex() {
        return modelIndex;
    }

    /**
     * @param modelIndex the modelIndex to set
     */
    public void setModelIndex(int modelIndex) {
        this.modelIndex = modelIndex;
    }
    /**
     * @return the textureIndex
     */
    public int getTextureIndex() {
        return textureIndex;
    }

    /**
     * @param textureIndex the textureIndex to set
     */
    public void setTextureIndex(int texture_index) {
        this.textureIndex = texture_index;
    }

//    /**
//     * @return the markers
//     */
//    public List<Marker> getMarkers() {
//        return markers;
//    }
//
//    /**
//     * @param markers the markers to set
//     */
//    public void setMarkers(List<Marker> markers) {
//        this.markers = markers;
//    }

    /**
     * @return the neighbourMap
     */
    public Tile[] getNeighbourMap() {
        return neighbourMap;
    }

    /**
     * @return the units
     */
    public HashMap<Player, ArrayList<UnitStack>> getUnits() {
        return units;
    }
}
